package com.homedo.async.mysql.support.prepare.update;

import com.blinkfox.zealot.bean.SqlInfo;
import com.blinkfox.zealot.core.ZealotKhala;
import com.google.common.collect.Lists;
import com.homedo.async.mysql.support.meta.EntityMetaData;
import com.homedo.async.mysql.support.prepare.util.CollectRecordColumnValUtil;
import com.homedo.plainly.logger.Logger;
import com.homedo.plainly.logger.LoggerFactory;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author jgshun
 * @date 2020/3/5 1:56 PM
 */
public abstract class Records2Sql4Update {
    private static final Logger _LOGGER = LoggerFactory.getLogger(Records2Sql4Update.class);


    public static <T> Object[] prepare(EntityMetaData<T> entityMetaData, Iterable<T> records, boolean includeNullVals) {
        Field primaryKeyField = entityMetaData.getPrimaryKeyField();
        if (primaryKeyField == null) {
            throw new RuntimeException("[主键不存在:" + entityMetaData.getEntityClazs() + "]");
        }

        String idColumnName = entityMetaData.getFieldColumNameMapping().get(primaryKeyField).toString();

        Object[] prepareSelectSql = new Object[2];

        ZealotKhala sqlKhala = ZealotKhala.start()
                .update(entityMetaData.getTableName());

        Iterator<T> recordIterator = records.iterator();

        List<Map<String, Object>> columnNameValMapList = Lists.newArrayList();

        while (recordIterator.hasNext()) {

            T record = recordIterator.next();

            Map<String, Object> columnNameValMap = CollectRecordColumnValUtil.collect(record, entityMetaData, includeNullVals);

            if (!columnNameValMap.isEmpty()) {
                columnNameValMapList.add(columnNameValMap);
            } else {
                _LOGGER.error("[缺少更新条件，禁止全表更新：{}]", sqlKhala.end().getSql());
                throw new RuntimeException("[缺少更新条件，禁止全表更新]");
            }
        }

        sqlKhala.set(" ");

        List<String> updateColumns = columnNameValMapList.get(0).entrySet().stream().filter(e -> !e.getKey().equals(idColumnName))
                .map(e -> e.getKey()).collect(Collectors.toList());

        List<Object> valParams = Lists.newArrayList();

        for (int i = 0; i < updateColumns.size(); i++) {
            String curColumn = updateColumns.get(i);

            if (i > 0) {
                sqlKhala.text(", ");
            }

            sqlKhala.text(curColumn).text(" = CASE ").text(idColumnName);

            columnNameValMapList.forEach(e -> {
                valParams.add(e.get(idColumnName));
                valParams.add(e.get(curColumn));

                sqlKhala.text(" WHEN  ? THEN ? ");
            });

            sqlKhala.text(" END ");
        }

        List<Object> idParams = columnNameValMapList.stream().map(e -> {
            return e.get(idColumnName);
        }).collect(Collectors.toList());

        sqlKhala.where(idColumnName).text(" IN ( ").text(idParams.stream().map(e -> " ? ").collect(Collectors.joining(", "))).text(" ) ");

        valParams.addAll(idParams);

        sqlKhala.param(valParams);

        SqlInfo sqlInfo = sqlKhala.end();

        prepareSelectSql[0] = sqlInfo.getSql();
        prepareSelectSql[1] = sqlInfo.getParams();

        return prepareSelectSql;
    }

}

